package com.xianyl.libsforandroid.utils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * Json Utils
 * @author xianyl
 * @date 2015-3-2 下午9:37:20
 */
public class JSONUtils {

	public static boolean isPrintException = true;

	/**
	 * 从 jsonObject获取长整型，封装对象类型
	 * 
	 * @param jsonObject
	 * @param key
	 * @param defaultValue
	 * @return <ul>
	 *         <li>if jsonObject is null, return defaultValue</li>
	 *         <li>if key is null or empty, return defaultValue</li>
	 *         <li>if {@link JSONObject#getLong(String)} exception, return
	 *         defaultValue</li>
	 *         <li>return {@link JSONObject#getLong(String)}</li>
	 *         </ul>
	 */
	public static Long getLong(JSONObject jsonObject, String key,
			Long defaultValue) {
		if (jsonObject == null || StringUtils.isEmpty(key)) {
			return defaultValue;
		}

		try {
			return jsonObject.getLong(key);
		} catch (JSONException e) {
			if (isPrintException) {
				e.printStackTrace();
			}
			return defaultValue;
		}
	}

	/**
	 * 从 jsonData字符串获取长整型，封装对象类型
	 * 
	 * @param jsonData
	 * @param key
	 * @param defaultValue
	 * @return <ul>
	 *         <li>if jsonObject is null, return defaultValue</li>
	 *         <li>if jsonData {@link JSONObject#JSONObject(String)} exception,
	 *         return defaultValue</li>
	 *         <li>return
	 *         {@link JSONUtils#getLong(JSONObject, String, JSONObject)}</li>
	 *         </ul>
	 */
	public static Long getLong(String jsonData, String key, Long defaultValue) {
		if (StringUtils.isEmpty(jsonData)) {
			return defaultValue;
		}

		try {
			JSONObject jsonObject = new JSONObject(jsonData);
			return getLong(jsonObject, key, defaultValue);
		} catch (JSONException e) {
			if (isPrintException) {
				e.printStackTrace();
			}
			return defaultValue;
		}
	}

	/**
	 * 从 jsonObject获取长整型，基本数据类型
	 * 
	 * @param jsonObject
	 * @param key
	 * @param defaultValue
	 * @return
	 * @see JSONUtils#getLong(JSONObject, String, Long)
	 */
	public static long getLong(JSONObject jsonObject, String key,
			long defaultValue) {
		return getLong(jsonObject, key, (Long) defaultValue);
	}

	/**
	 * 从 jsonData字符串获取长整型，基本数据类型
	 * 
	 * @param jsonData
	 * @param key
	 * @param defaultValue
	 * @return
	 * @see JSONUtils#getLong(String, String, Long)
	 */
	public static long getLong(String jsonData, String key, long defaultValue) {
		return getLong(jsonData, key, (Long) defaultValue);
	}

	/**
	 * 从 JSONObject获取整型，封装对象类型
	 * 
	 * @param jsonObject
	 * @param key
	 * @param defaultValue
	 * @return <ul>
	 *         <li>if jsonObject is null, return defaultValue</li>
	 *         <li>if key is null or empty, return defaultValue</li>
	 *         <li>if {@link JSONObject#getInt(String)} exception, return
	 *         defaultValue</li>
	 *         <li>return {@link JSONObject#getInt(String)}</li>
	 *         </ul>
	 */
	public static Integer getInt(JSONObject jsonObject, String key,
			Integer defaultValue) {
		if (jsonObject == null || StringUtils.isEmpty(key)) {
			return defaultValue;
		}

		try {
			return jsonObject.getInt(key);
		} catch (JSONException e) {
			if (isPrintException) {
				e.printStackTrace();
			}
			return defaultValue;
		}
	}

	/**
	 * 从 jsonData字符串获取整型，封装对象类型
	 * 
	 * @param jsonData
	 * @param key
	 * @param defaultValue
	 * @return <ul>
	 *         <li>if jsonObject is null, return defaultValue</li>
	 *         <li>if jsonData {@link JSONObject#JSONObject(String)} exception,
	 *         return defaultValue</li>
	 *         <li>return
	 *         {@link JSONUtils#getInt(JSONObject, String, JSONObject)}</li>
	 *         </ul>
	 */
	public static Integer getInt(String jsonData, String key,
			Integer defaultValue) {
		if (StringUtils.isEmpty(jsonData)) {
			return defaultValue;
		}

		try {
			JSONObject jsonObject = new JSONObject(jsonData);
			return getInt(jsonObject, key, defaultValue);
		} catch (JSONException e) {
			if (isPrintException) {
				e.printStackTrace();
			}
			return defaultValue;
		}
	}

	/**
	 * 从 JSONObject获取整型，基本类型
	 * 
	 * @param jsonObject
	 * @param key
	 * @param defaultValue
	 * @return
	 * @see JSONUtils#getInt(JSONObject, String, Integer)
	 */
	public static int getInt(JSONObject jsonObject, String key, int defaultValue) {
		return getInt(jsonObject, key, (Integer) defaultValue);
	}

	/**
	 * 从 jsonData字符串获取整型，基本类型
	 * 
	 * @param jsonObject
	 * @param key
	 * @param defaultValue
	 * @return
	 * @see JSONUtils#getInt(String, String, Integer)
	 */
	public static int getInt(String jsonData, String key, int defaultValue) {
		return getInt(jsonData, key, (Integer) defaultValue);
	}

	/**
	 * 从 JSONObject获取双精度浮点数据型，封装对象类型
	 * 
	 * @param jsonObject
	 * @param key
	 * @param defaultValue
	 * @return <ul>
	 *         <li>if jsonObject is null, return defaultValue</li>
	 *         <li>if key is null or empty, return defaultValue</li>
	 *         <li>if {@link JSONObject#getDouble(String)} exception, return
	 *         defaultValue</li>
	 *         <li>return {@link JSONObject#getDouble(String)}</li>
	 *         </ul>
	 */
	public static Double getDouble(JSONObject jsonObject, String key,
			Double defaultValue) {
		if (jsonObject == null || StringUtils.isEmpty(key)) {
			return defaultValue;
		}

		try {
			return jsonObject.getDouble(key);
		} catch (JSONException e) {
			if (isPrintException) {
				e.printStackTrace();
			}
			return defaultValue;
		}
	}

	/**
	 * 从 jsonData字符串获取双精度浮点数据型，封装对象类型
	 * 
	 * @param jsonData
	 * @param key
	 * @param defaultValue
	 * @return <ul>
	 *         <li>if jsonObject is null, return defaultValue</li>
	 *         <li>if jsonData {@link JSONObject#JSONObject(String)} exception,
	 *         return defaultValue</li>
	 *         <li>return
	 *         {@link JSONUtils#getDouble(JSONObject, String, JSONObject)}</li>
	 *         </ul>
	 */
	public static Double getDouble(String jsonData, String key,
			Double defaultValue) {
		if (StringUtils.isEmpty(jsonData)) {
			return defaultValue;
		}

		try {
			JSONObject jsonObject = new JSONObject(jsonData);
			return getDouble(jsonObject, key, defaultValue);
		} catch (JSONException e) {
			if (isPrintException) {
				e.printStackTrace();
			}
			return defaultValue;
		}
	}

	/**
	 * 从 JSONObject获取双精度浮点数据型，基本类型
	 * 
	 * @param jsonObject
	 * @param key
	 * @param defaultValue
	 * @return
	 * @see JSONUtils#getDouble(JSONObject, String, Double)
	 */
	public static double getDouble(JSONObject jsonObject, String key,
			double defaultValue) {
		return getDouble(jsonObject, key, (Double) defaultValue);
	}

	/**
	 * 从 jsonData字符串获取双精度浮点数据型，基本类型
	 * 
	 * @param jsonObject
	 * @param key
	 * @param defaultValue
	 * @return
	 * @see JSONUtils#getDouble(String, String, Double)
	 */
	public static double getDouble(String jsonData, String key,
			double defaultValue) {
		return getDouble(jsonData, key, (Double) defaultValue);
	}

	/**
	 * 从 JSONObject获取字符串
	 * 
	 * @param jsonObject
	 * @param key
	 * @param defaultValue
	 * @return <ul>
	 *         <li>if jsonObject is null, return defaultValue</li>
	 *         <li>if key is null or empty, return defaultValue</li>
	 *         <li>if {@link JSONObject#getString(String)} exception, return
	 *         defaultValue</li>
	 *         <li>return {@link JSONObject#getString(String)}</li>
	 *         </ul>
	 */
	public static String getString(JSONObject jsonObject, String key,
			String defaultValue) {
		if (jsonObject == null || StringUtils.isEmpty(key)) {
			return defaultValue;
		}

		try {
			return jsonObject.getString(key);
		} catch (JSONException e) {
			if (isPrintException) {
				e.printStackTrace();
			}
			return defaultValue;
		}
	}

	/**
	 * 从 jsonData字符串获取字符串
	 * 
	 * @param jsonData
	 * @param key
	 * @param defaultValue
	 * @return <ul>
	 *         <li>if jsonObject is null, return defaultValue</li>
	 *         <li>if jsonData {@link JSONObject#JSONObject(String)} exception,
	 *         return defaultValue</li>
	 *         <li>return
	 *         {@link JSONUtils#getString(JSONObject, String, JSONObject)}</li>
	 *         </ul>
	 */
	public static String getString(String jsonData, String key,
			String defaultValue) {
		if (StringUtils.isEmpty(jsonData)) {
			return defaultValue;
		}

		try {
			JSONObject jsonObject = new JSONObject(jsonData);
			return getString(jsonObject, key, defaultValue);
		} catch (JSONException e) {
			if (isPrintException) {
				e.printStackTrace();
			}
			return defaultValue;
		}
	}

	/**
	 * 从 JSONObject获取字符串数组
	 * 
	 * @param jsonObject
	 * @param key
	 * @param defaultValue
	 * @return <ul>
	 *         <li>if jsonObject is null, return defaultValue</li>
	 *         <li>if key is null or empty, return defaultValue</li>
	 *         <li>if {@link JSONObject#getJSONArray(String)} exception, return
	 *         defaultValue</li>
	 *         <li>if {@link JSONArray#getString(int)} exception, return
	 *         defaultValue</li>
	 *         <li>return string array</li>
	 *         </ul>
	 */
	public static String[] getStringArray(JSONObject jsonObject, String key,
			String[] defaultValue) {
		if (jsonObject == null || StringUtils.isEmpty(key)) {
			return defaultValue;
		}

		try {
			JSONArray statusArray = jsonObject.getJSONArray(key);
			if (statusArray != null) {
				String[] value = new String[statusArray.length()];
				for (int i = 0; i < statusArray.length(); i++) {
					value[i] = statusArray.getString(i);
				}
				return value;
			}
		} catch (JSONException e) {
			if (isPrintException) {
				e.printStackTrace();
			}
			return defaultValue;
		}
		return defaultValue;
	}

	/**
	 * 从 jsonData字符串获取字符串数组
	 * 
	 * @param jsonData
	 * @param key
	 * @param defaultValue
	 * @return <ul>
	 *         <li>if jsonObject is null, return defaultValue</li>
	 *         <li>if jsonData {@link JSONObject#JSONObject(String)} exception,
	 *         return defaultValue</li>
	 *         <li>return
	 *         {@link JSONUtils#getStringArray(JSONObject, String, JSONObject)}</li>
	 *         </ul>
	 */
	public static String[] getStringArray(String jsonData, String key,
			String[] defaultValue) {
		if (StringUtils.isEmpty(jsonData)) {
			return defaultValue;
		}

		try {
			JSONObject jsonObject = new JSONObject(jsonData);
			return getStringArray(jsonObject, key, defaultValue);
		} catch (JSONException e) {
			if (isPrintException) {
				e.printStackTrace();
			}
			return defaultValue;
		}
	}

	/**
	 * 从 JSONObject获取JSONObject对象
	 * 
	 * @param jsonObject
	 *            <em><em></em></em>
	 * @param key
	 * @param defaultValue
	 * @return <ul>
	 *         <li>if jsonObject is null, return defaultValue</li>
	 *         <li>if key is null or empty, return defaultValue</li>
	 *         <li>if {@link JSONObject#getJSONObject(String)} exception, return
	 *         defaultValue</li>
	 *         <li>return {@link JSONObject#getJSONObject(String)}</li>
	 *         </ul>
	 */
	public static JSONObject getJSONObject(JSONObject jsonObject, String key,
			JSONObject defaultValue) {
		if (jsonObject == null || StringUtils.isEmpty(key)) {
			return defaultValue;
		}

		try {
			return jsonObject.getJSONObject(key);
		} catch (JSONException e) {
			if (isPrintException) {
				e.printStackTrace();
			}
			return defaultValue;
		}
	}

	/**
	 * 从jsonData字符串获取JSONObject对象
	 * 
	 * @param jsonData
	 * @param key
	 * @param defaultValue
	 * @return <ul>
	 *         <li>if jsonObject is null, return defaultValue</li>
	 *         <li>if jsonData {@link JSONObject#JSONObject(String)} exception,
	 *         return defaultValue</li>
	 *         <li>return
	 *         {@link JSONUtils#getJSONObject(JSONObject, String, JSONObject)}</li>
	 *         </ul>
	 */
	public static JSONObject getJSONObject(String jsonData, String key,
			JSONObject defaultValue) {
		if (StringUtils.isEmpty(jsonData)) {
			return defaultValue;
		}

		try {
			JSONObject jsonObject = new JSONObject(jsonData);
			return getJSONObject(jsonObject, key, defaultValue);
		} catch (JSONException e) {
			if (isPrintException) {
				e.printStackTrace();
			}
			return defaultValue;
		}
	}

	/**
	 * 从JSONObject获取JSONArray对象
	 * 
	 * @param jsonObject
	 * @param key
	 * @param defaultValue
	 * @return <ul>
	 *         <li>if jsonObject is null, return defaultValue</li>
	 *         <li>if key is null or empty, return defaultValue</li>
	 *         <li>if {@link JSONObject#getJSONArray(String)} exception, return
	 *         defaultValue</li>
	 *         <li>return {@link JSONObject#getJSONArray(String)}</li>
	 *         </ul>
	 */
	public static JSONArray getJSONArray(JSONObject jsonObject, String key,
			JSONArray defaultValue) {
		if (jsonObject == null || StringUtils.isEmpty(key)) {
			return defaultValue;
		}

		try {
			return jsonObject.getJSONArray(key);
		} catch (JSONException e) {
			if (isPrintException) {
				e.printStackTrace();
			}
			return defaultValue;
		}
	}

	/**
	 * 从jsonData字符串获取JSONArray对象
	 * 
	 * @param jsonData
	 * @param key
	 * @param defaultValue
	 * @return <ul>
	 *         <li>if jsonObject is null, return defaultValue</li>
	 *         <li>if jsonData {@link JSONObject#JSONObject(String)} exception,
	 *         return defaultValue</li>
	 *         <li>return
	 *         {@link JSONUtils#getJSONArray(JSONObject, String, JSONObject)}</li>
	 *         </ul>
	 */
	public static JSONArray getJSONArray(String jsonData, String key,
			JSONArray defaultValue) {
		if (StringUtils.isEmpty(jsonData)) {
			return defaultValue;
		}

		try {
			JSONObject jsonObject = new JSONObject(jsonData);
			return getJSONArray(jsonObject, key, defaultValue);
		} catch (JSONException e) {
			if (isPrintException) {
				e.printStackTrace();
			}
			return defaultValue;
		}
	}

	/**
	 * 从JSONObject获取布尔类型数据
	 * 
	 * @param jsonObject
	 * @param key
	 * @param defaultValue
	 * @return <ul>
	 *         <li>if jsonObject is null, return defaultValue</li>
	 *         <li>if key is null or empty, return defaultValue</li>
	 *         <li>return {@link JSONObject#getBoolean(String)}</li>
	 *         </ul>
	 */
	public static boolean getBoolean(JSONObject jsonObject, String key,
			Boolean defaultValue) {
		if (jsonObject == null || StringUtils.isEmpty(key)) {
			return defaultValue;
		}

		try {
			return jsonObject.getBoolean(key);
		} catch (JSONException e) {
			if (isPrintException) {
				e.printStackTrace();
			}
			return defaultValue;
		}
	}

	/**
	 * 从jsonData字符串获取布尔类型数据
	 * 
	 * @param jsonData
	 * @param key
	 * @param defaultValue
	 * @return <ul>
	 *         <li>if jsonObject is null, return defaultValue</li>
	 *         <li>if jsonData {@link JSONObject#JSONObject(String)} exception,
	 *         return defaultValue</li>
	 *         <li>return
	 *         {@link JSONUtils#getBoolean(JSONObject, String, Boolean)}</li>
	 *         </ul>
	 */
	public static boolean getBoolean(String jsonData, String key,
			Boolean defaultValue) {
		if (StringUtils.isEmpty(jsonData)) {
			return defaultValue;
		}

		try {
			JSONObject jsonObject = new JSONObject(jsonData);
			return getBoolean(jsonObject, key, defaultValue);
		} catch (JSONException e) {
			if (isPrintException) {
				e.printStackTrace();
			}
			return defaultValue;
		}
	}

	/**
	 * 从JSONObject获取 map对象
	 * 
	 * @param jsonObject
	 *            key-value pairs json
	 * @param key
	 * @return <ul>
	 *         <li>if jsonObject is null, return null</li>
	 *         <li>return {@link JSONUtils#parseKeyAndValueToMap(String)}</li>
	 *         </ul>
	 */
	public static Map<String, String> getMap(JSONObject jsonObject, String key) {
		return JSONUtils.parseKeyAndValueToMap(getString(jsonObject,key, null));
	}

	/**
	 * 从jsonData字符串获取 map对象
	 * 
	 * @param jsonData
	 *            key-value pairs string
	 * @param key
	 * @return <ul>
	 *         <li>if jsonData is null, return null</li>
	 *         <li>if jsonData length is 0, return empty map</li>
	 *         <li>if jsonData {@link JSONObject#JSONObject(String)} exception,
	 *         return null</li>
	 *         <li>return {@link JSONUtils#getMap(JSONObject, String)}</li>
	 *         </ul>
	 */
	public static Map<String, String> getMap(String jsonData, String key) {

		if (jsonData == null) {
			return null;
		}
		if (jsonData.length() == 0) {
			return new HashMap<String, String>();
		}

		try {
			JSONObject jsonObject = new JSONObject(jsonData);
			return getMap(jsonObject, key);
		} catch (JSONException e) {
			if (isPrintException) {
				e.printStackTrace();
			}
			return null;
		}
	}

	/**
	 * 从JSONObject解释数据到 map对象
	 * 
	 * @param sourceObj key-value对的 json
	 * @return <ul>
	 *         <li>if source 为空, return null</li>
	 *         <li>else 解析 entry 在{@link MapUtils#putMapNotEmptyKey(Map, String, String)}一个一个加入</li>
	 *         </ul>
	 */
	@SuppressWarnings("rawtypes")
	public static Map<String, String> parseKeyAndValueToMap(JSONObject sourceObj) {
		if (sourceObj == null) {
			return null;
		}

		Map<String, String> keyAndValueMap = new HashMap<String, String>();
		for (Iterator iter = sourceObj.keys(); iter.hasNext();) {
			String key = (String) iter.next();
			MapUtils.putMapNotEmptyKey(keyAndValueMap, key,
					getString(sourceObj, key, ""));

		}
		return keyAndValueMap;
	}

	/**
	 * 从source字符串解释数据到 map对象
	 * 
	 * @param source key-value对的 json
	 * @return <ul>
	 *         <li>if source 为空或者长度等于0, return null</li>
	 *         <li>if source {@link JSONObject#JSONObject(String)} exception,
	 *         return null</li>
	 *         <li>return {@link JSONUtils#parseKeyAndValueToMap(JSONObject)}</li>
	 *         </ul>
	 */
	public static Map<String, String> parseKeyAndValueToMap(String source) {
		if (StringUtils.isEmpty(source)) {
			return null;
		}

		try {
			JSONObject jsonObject = new JSONObject(source);
			return parseKeyAndValueToMap(jsonObject);
		} catch (JSONException e) {
			if (isPrintException) {
				e.printStackTrace();
			}
			return null;
		}
	}
	
	
	/**
	 * 根据 JSONArray 建立MapList,map是对象
	 * @param jsonArray
	 * @return
	 */
	public static ArrayList<Map<String, String>> toMapList(JSONArray jsonArray){
		if (jsonArray == null) {
			return null;
		}		
		ArrayList<Map<String, String>> list = new ArrayList<Map<String, String>>();
		for (int i = 0; i < jsonArray.length(); i++) {
			try {
				list.add(parseKeyAndValueToMap(jsonArray.getJSONObject(i)));
			} catch (JSONException e) {
				e.printStackTrace();
			}
		}
		return list;
	}
	
	/**
	 * 根据 jsonData 建立MapList,map是对象
	 * @param jsonData json字符串
	 * @param key {@link #getJSONArray(String, String, JSONArray)}
	 * @return
	 */
	public static ArrayList<Map<String, String>> toMapList(String jsonData, String key){
		return toMapList(getJSONArray(jsonData, key, null));
	}

	
	
	/**
	 * 根据 JSONObject 建立bean
	 * 
	 * @param jsonObject
	 * @param bean
	 * @return
	 * @throws Exception
	 */
	public static <T> T toBean(JSONObject jsonObject, T bean) throws JSONException{
		if (jsonObject == null || bean == null) {
			return bean;
		}
		Class<? extends Object> beanClass = bean.getClass();
		if (beanClass.isInterface()) {
			throw new JSONException("bean是一个接口 " + beanClass);
		}
		// 获取属性字段。
		Field[] fields = beanClass.getDeclaredFields();
		for (Field field : fields) {
			String fieldName = field.getName();
			try {
				//这里需要把jsonObject.get(fieldName)的异常处理，可以跳过单个方法 
				ObjectUtils.invokeSet(bean, fieldName, jsonObject.get(fieldName));
			} catch (JSONException e) {
				e.printStackTrace();
			}
		}

		return bean;
	}
	
	
	
	

	/**
	 * 根据 JSONArray 建立beanList
	 * 
	 * @param jsonArray
	 * @param beanClass
	 * @return
	 * @throws Exception
	 */
	public static <T> ArrayList<T> toBeanList(JSONArray jsonArray,
			Class<T> beanClass) throws Exception {
		if (jsonArray == null || beanClass == null) {
			return null;
		}
		if (beanClass.isInterface()) {
			throw new JSONException("bean是一个接口 " + beanClass);
		}
		ArrayList<T> list = new ArrayList<T>();
		for (int i = 0; i < jsonArray.length(); i++) {			
			list.add(toBean(jsonArray.getJSONObject(i), beanClass.newInstance()));
		}
		return list;
	}

	/**
	 * 根据 jsonData 建立beanList
	 * @param jsonData json字符串
	 * @param key {@link #getJSONArray(String, String, JSONArray)}
	 * @param beanClass
	 * @return
	 * @throws Exception
	 */
	public static <T> ArrayList<T> toBeanList(String jsonData, String key,
			Class<T> beanClass) throws Exception {
		return toBeanList(getJSONArray(jsonData, key, null), beanClass);
	}

}
